projects/linux·blob master · refs

120 lines · 2.9 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * llc_station.c - station component of LLC
4 *
5 * Copyright (c) 1997 by Procom Technology, Inc.
6 * 2001-2003 by Arnaldo Carvalho de Melo <[email protected]>
7 */
8#include <linux/init.h>
9#include <linux/module.h>
10#include <linux/slab.h>
11#include <net/llc.h>
12#include <net/llc_sap.h>
13#include <net/llc_conn.h>
14#include <net/llc_c_ac.h>
15#include <net/llc_s_ac.h>
16#include <net/llc_c_ev.h>
17#include <net/llc_c_st.h>
18#include <net/llc_s_ev.h>
19#include <net/llc_s_st.h>
20#include <net/llc_pdu.h>
21
22static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
23{
24 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
25
26 return LLC_PDU_IS_CMD(pdu) && /* command PDU */
27 LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
28 LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
29 !pdu->dsap; /* NULL DSAP value */
30}
31
32static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
33{
34 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
35
36 return LLC_PDU_IS_CMD(pdu) && /* command PDU */
37 LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
38 LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
39 !pdu->dsap; /* NULL DSAP */
40}
41
42static int llc_station_ac_send_xid_r(struct sk_buff *skb)
43{
44 u8 mac_da[ETH_ALEN], dsap;
45 int rc = 1;
46 struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U,
47 sizeof(struct llc_xid_info));
48
49 if (!nskb)
50 goto out;
51 llc_pdu_decode_sa(skb, mac_da);
52 llc_pdu_decode_ssap(skb, &dsap);
53 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
54 llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
55 rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
56 if (unlikely(rc))
57 goto free;
58 dev_queue_xmit(nskb);
59out:
60 return rc;
61free:
62 kfree_skb(nskb);
63 goto out;
64}
65
66static int llc_station_ac_send_test_r(struct sk_buff *skb)
67{
68 u8 mac_da[ETH_ALEN], dsap;
69 int rc = 1;
70 u32 data_size;
71 struct sk_buff *nskb;
72
73 if (skb->mac_len < ETH_HLEN)
74 goto out;
75
76 /* The test request command is type U (llc_len = 3) */
77 data_size = ntohs(eth_hdr(skb)->h_proto) - 3;
78 nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
79
80 if (!nskb)
81 goto out;
82 llc_pdu_decode_sa(skb, mac_da);
83 llc_pdu_decode_ssap(skb, &dsap);
84 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
85 llc_pdu_init_as_test_rsp(nskb, skb);
86 rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
87 if (unlikely(rc))
88 goto free;
89 dev_queue_xmit(nskb);
90out:
91 return rc;
92free:
93 kfree_skb(nskb);
94 goto out;
95}
96
97/**
98 * llc_station_rcv - send received pdu to the station state machine
99 * @skb: received frame.
100 *
101 * Sends data unit to station state machine.
102 */
103static void llc_station_rcv(struct sk_buff *skb)
104{
105 if (llc_stat_ev_rx_null_dsap_xid_c(skb))
106 llc_station_ac_send_xid_r(skb);
107 else if (llc_stat_ev_rx_null_dsap_test_c(skb))
108 llc_station_ac_send_test_r(skb);
109 kfree_skb(skb);
110}
111
112void __init llc_station_init(void)
113{
114 llc_set_station_handler(llc_station_rcv);
115}
116
117void llc_station_exit(void)
118{
119 llc_set_station_handler(NULL);
120}