11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * llc_station.c - station component of LLC 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1997 by Procom Technology, Inc. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program can be redistributed or modified under the terms of the 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License as published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed without any warranty or implied warranty 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of merchantability or fitness for a particular purpose. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See the GNU General Public License for more details. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 165a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_sap.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_conn.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_c_ac.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_s_ac.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_c_ev.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_c_st.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_s_ev.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_s_st.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/llc_pdu.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb) 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32025e36332573177ecd7c12730e18a4390f994f05Ben Hutchings return LLC_PDU_IS_CMD(pdu) && /* command PDU */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !pdu->dsap ? 0 : 1; /* NULL DSAP value */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42025e36332573177ecd7c12730e18a4390f994f05Ben Hutchings return LLC_PDU_IS_CMD(pdu) && /* command PDU */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !pdu->dsap ? 0 : 1; /* NULL DSAP */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int llc_station_ac_send_xid_r(struct sk_buff *skb) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 mac_da[ETH_ALEN], dsap; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 1; 52f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, 53f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park sizeof(struct llc_xid_info)); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nskb) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_decode_sa(skb, mac_da); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_decode_ssap(skb, &dsap); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127); 62a5a04819c5740cb1aa217af2cc8f5ef26f33d744Joonwoo Park rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da); 63249ff1c6d35fd32ca945967c3f0b948210a96baaArnaldo Carvalho de Melo if (unlikely(rc)) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 655ecf9eea2660c4fe894fabd3c3d0b64860fb0160Ben Hutchings dev_queue_xmit(nskb); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree: 6991d27a8650d5359a7a320daeb35b88cdea15e3a8Sorin Dumitru kfree_skb(nskb); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int llc_station_ac_send_test_r(struct sk_buff *skb) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 mac_da[ETH_ALEN], dsap; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 1; 77f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park u32 data_size; 78f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park struct sk_buff *nskb; 79f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park 80f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park /* The test request command is type U (llc_len = 3) */ 81f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park data_size = ntohs(eth_hdr(skb)->h_proto) - 3; 82f83f1768f833cb45bc93429fdc552252a4f55ac3Joonwoo Park nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nskb) 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_decode_sa(skb, mac_da); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_decode_ssap(skb, &dsap); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); 90d57b1869b231c56de441db35c647879d51c5d29eYOSHIFUJI Hideaki llc_pdu_init_as_test_rsp(nskb, skb); 91a5a04819c5740cb1aa217af2cc8f5ef26f33d744Joonwoo Park rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da); 92249ff1c6d35fd32ca945967c3f0b948210a96baaArnaldo Carvalho de Melo if (unlikely(rc)) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 945ecf9eea2660c4fe894fabd3c3d0b64860fb0160Ben Hutchings dev_queue_xmit(nskb); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree: 9891d27a8650d5359a7a320daeb35b88cdea15e3a8Sorin Dumitru kfree_skb(nskb); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * llc_station_rcv - send received pdu to the station state machine 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @skb: received frame. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sends data unit to station state machine. 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void llc_station_rcv(struct sk_buff *skb) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11012ebc8b9af7e29ff4dc77ee0e73a6b1de513d659Ben Hutchings if (llc_stat_ev_rx_null_dsap_xid_c(skb)) 11112ebc8b9af7e29ff4dc77ee0e73a6b1de513d659Ben Hutchings llc_station_ac_send_xid_r(skb); 11212ebc8b9af7e29ff4dc77ee0e73a6b1de513d659Ben Hutchings else if (llc_stat_ev_rx_null_dsap_test_c(skb)) 11312ebc8b9af7e29ff4dc77ee0e73a6b1de513d659Ben Hutchings llc_station_ac_send_test_r(skb); 11404d191c259e2a2832ea7aef14cb02fe03a71d51fBen Hutchings kfree_skb(skb); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1176024935f5ff5f1646bce8404416318e5fd4a0c4aBen Hutchingsvoid __init llc_station_init(void) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 119aadf31de16a7b2878af00a02e6557df84efa784bBen Hutchings llc_set_station_handler(llc_station_rcv); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122f4f8720febf0d785a054fc09bde5e3ad09728a58Ben Hutchingsvoid llc_station_exit(void) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc_set_station_handler(NULL); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 126