1cb9cadadSEd Warnicke/*
2cb9cadadSEd Warnicke * Copyright (c) 2015 Cisco and/or its affiliates.
3cb9cadadSEd Warnicke * Licensed under the Apache License, Version 2.0 (the "License");
4cb9cadadSEd Warnicke * you may not use this file except in compliance with the License.
5cb9cadadSEd Warnicke * You may obtain a copy of the License at:
6cb9cadadSEd Warnicke *
7cb9cadadSEd Warnicke *     http://www.apache.org/licenses/LICENSE-2.0
8cb9cadadSEd Warnicke *
9cb9cadadSEd Warnicke * Unless required by applicable law or agreed to in writing, software
10cb9cadadSEd Warnicke * distributed under the License is distributed on an "AS IS" BASIS,
11cb9cadadSEd Warnicke * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb9cadadSEd Warnicke * See the License for the specific language governing permissions and
13cb9cadadSEd Warnicke * limitations under the License.
14cb9cadadSEd Warnicke */
15cb9cadadSEd Warnicke/*
16cb9cadadSEd Warnicke * hdlc.c: hdlc
17cb9cadadSEd Warnicke *
18cb9cadadSEd Warnicke * Copyright (c) 2010 Eliot Dresselhaus
19cb9cadadSEd Warnicke *
20cb9cadadSEd Warnicke * Permission is hereby granted, free of charge, to any person obtaining
21cb9cadadSEd Warnicke * a copy of this software and associated documentation files (the
22cb9cadadSEd Warnicke * "Software"), to deal in the Software without restriction, including
23cb9cadadSEd Warnicke * without limitation the rights to use, copy, modify, merge, publish,
24cb9cadadSEd Warnicke * distribute, sublicense, and/or sell copies of the Software, and to
25cb9cadadSEd Warnicke * permit persons to whom the Software is furnished to do so, subject to
26cb9cadadSEd Warnicke * the following conditions:
27cb9cadadSEd Warnicke *
28cb9cadadSEd Warnicke * The above copyright notice and this permission notice shall be
29cb9cadadSEd Warnicke * included in all copies or substantial portions of the Software.
30cb9cadadSEd Warnicke *
31cb9cadadSEd Warnicke *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32cb9cadadSEd Warnicke *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33cb9cadadSEd Warnicke *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34cb9cadadSEd Warnicke *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35cb9cadadSEd Warnicke *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36cb9cadadSEd Warnicke *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37cb9cadadSEd Warnicke *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38cb9cadadSEd Warnicke */
39cb9cadadSEd Warnicke
40cb9cadadSEd Warnicke#include <vnet/vnet.h>
41cb9cadadSEd Warnicke#include <vnet/hdlc/hdlc.h>
42cb9cadadSEd Warnicke
43cb9cadadSEd Warnicke/* Global main structure. */
44cb9cadadSEd Warnickehdlc_main_t hdlc_main;
45cb9cadadSEd Warnicke
46cc42db82SSwarup Nayaku8 *
47cc42db82SSwarup Nayakformat_hdlc_protocol (u8 * s, va_list * args)
48cb9cadadSEd Warnicke{
49cb9cadadSEd Warnicke  hdlc_protocol_t p = va_arg (*args, u32);
50cc42db82SSwarup Nayak  hdlc_main_t *pm = &hdlc_main;
51cc42db82SSwarup Nayak  hdlc_protocol_info_t *pi = hdlc_get_protocol_info (pm, p);
52cb9cadadSEd Warnicke
53cb9cadadSEd Warnicke  if (pi)
54cb9cadadSEd Warnicke    s = format (s, "%s", pi->name);
55cb9cadadSEd Warnicke  else
56cb9cadadSEd Warnicke    s = format (s, "0x%04x", p);
57cb9cadadSEd Warnicke
58cb9cadadSEd Warnicke  return s;
59cb9cadadSEd Warnicke}
60cb9cadadSEd Warnicke
61cc42db82SSwarup Nayaku8 *
62cc42db82SSwarup Nayakformat_hdlc_header_with_length (u8 * s, va_list * args)
63cb9cadadSEd Warnicke{
64cc42db82SSwarup Nayak  hdlc_main_t *pm = &hdlc_main;
65cc42db82SSwarup Nayak  hdlc_header_t *h = va_arg (*args, hdlc_header_t *);
66cb9cadadSEd Warnicke  u32 max_header_bytes = va_arg (*args, u32);
67cb9cadadSEd Warnicke  hdlc_protocol_t p = clib_net_to_host_u16 (h->protocol);
68d3c008d1SChristophe Fontaine  u32 indent, header_bytes;
69cb9cadadSEd Warnicke
70cb9cadadSEd Warnicke  header_bytes = sizeof (h[0]);
71cb9cadadSEd Warnicke  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
72cb9cadadSEd Warnicke    return format (s, "hdlc header truncated");
73cb9cadadSEd Warnicke
74cb9cadadSEd Warnicke  indent = format_get_indent (s);
75cb9cadadSEd Warnicke
76cb9cadadSEd Warnicke  s = format (s, "HDLC %U", format_hdlc_protocol, p);
77cb9cadadSEd Warnicke
78cb9cadadSEd Warnicke  if (h->address != 0xff)
79cb9cadadSEd Warnicke    s = format (s, ", address 0x%02x", h->address);
80cb9cadadSEd Warnicke  if (h->control != 0x03)
81cb9cadadSEd Warnicke    s = format (s, ", control 0x%02x", h->control);
82cb9cadadSEd Warnicke
83cb9cadadSEd Warnicke  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
84cb9cadadSEd Warnicke    {
85cc42db82SSwarup Nayak      hdlc_protocol_info_t *pi = hdlc_get_protocol_info (pm, p);
86cc42db82SSwarup Nayak      vlib_node_t *node = vlib_get_node (pm->vlib_main, pi->node_index);
87cb9cadadSEd Warnicke      if (node->format_buffer)
88cb9cadadSEd Warnicke	s = format (s, "\n%U%U",
89cb9cadadSEd Warnicke		    format_white_space, indent,
90cb9cadadSEd Warnicke		    node->format_buffer, (void *) (h + 1),
91cb9cadadSEd Warnicke		    max_header_bytes - header_bytes);
92cb9cadadSEd Warnicke    }
93cb9cadadSEd Warnicke
94cb9cadadSEd Warnicke  return s;
95cb9cadadSEd Warnicke}
96cb9cadadSEd Warnicke
97cc42db82SSwarup Nayaku8 *
98cc42db82SSwarup Nayakformat_hdlc_header (u8 * s, va_list * args)
99cb9cadadSEd Warnicke{
100cc42db82SSwarup Nayak  hdlc_header_t *h = va_arg (*args, hdlc_header_t *);
101cb9cadadSEd Warnicke  return format (s, "%U", format_hdlc_header_with_length, h, 0);
102cb9cadadSEd Warnicke}
103cb9cadadSEd Warnicke
104cb9cadadSEd Warnicke/* Returns hdlc protocol as an int in host byte order. */
105cb9cadadSEd Warnickeuword
106cb9cadadSEd Warnickeunformat_hdlc_protocol_host_byte_order (unformat_input_t * input,
107cc42db82SSwarup Nayak					va_list * args)
108cb9cadadSEd Warnicke{
109cc42db82SSwarup Nayak  u16 *result = va_arg (*args, u16 *);
110cc42db82SSwarup Nayak  hdlc_main_t *pm = &hdlc_main;
111cb9cadadSEd Warnicke  int p, i;
112cb9cadadSEd Warnicke
113cb9cadadSEd Warnicke  /* Numeric type. */
114cc42db82SSwarup Nayak  if (unformat (input, "0x%x", &p) || unformat (input, "%d", &p))
115cb9cadadSEd Warnicke    {
116cb9cadadSEd Warnicke      if (p >= (1 << 16))
117cb9cadadSEd Warnicke	return 0;
118cb9cadadSEd Warnicke      *result = p;
119cb9cadadSEd Warnicke      return 1;
120cb9cadadSEd Warnicke    }
121cb9cadadSEd Warnicke
122cb9cadadSEd Warnicke  /* Named type. */
123cb9cadadSEd Warnicke  if (unformat_user (input, unformat_vlib_number_by_name,
124cb9cadadSEd Warnicke		     pm->protocol_info_by_name, &i))
125cb9cadadSEd Warnicke    {
126cc42db82SSwarup Nayak      hdlc_protocol_info_t *pi = vec_elt_at_index (pm->protocol_infos, i);
127cb9cadadSEd Warnicke      *result = pi->protocol;
128cb9cadadSEd Warnicke      return 1;
129cb9cadadSEd Warnicke    }
130cb9cadadSEd Warnicke
131cb9cadadSEd Warnicke  return 0;
132cb9cadadSEd Warnicke}
133cb9cadadSEd Warnicke
134cb9cadadSEd Warnickeuword
135cb9cadadSEd Warnickeunformat_hdlc_protocol_net_byte_order (unformat_input_t * input,
136cc42db82SSwarup Nayak				       va_list * args)
137cb9cadadSEd Warnicke{
138cc42db82SSwarup Nayak  u16 *result = va_arg (*args, u16 *);
139cc42db82SSwarup Nayak  if (!unformat_user (input, unformat_hdlc_protocol_host_byte_order, result))
140cb9cadadSEd Warnicke    return 0;
141cc42db82SSwarup Nayak  *result = clib_host_to_net_u16 ((u16) * result);
142cb9cadadSEd Warnicke  return 1;
143cb9cadadSEd Warnicke}
144cb9cadadSEd Warnicke
145cb9cadadSEd Warnickeuword
146cb9cadadSEd Warnickeunformat_hdlc_header (unformat_input_t * input, va_list * args)
147cb9cadadSEd Warnicke{
148cc42db82SSwarup Nayak  u8 **result = va_arg (*args, u8 **);
149cc42db82SSwarup Nayak  hdlc_header_t _h, *h = &_h;
150cb9cadadSEd Warnicke  u16 p;
151cb9cadadSEd Warnicke
152cc42db82SSwarup Nayak  if (!unformat (input, "%U", unformat_hdlc_protocol_host_byte_order, &p))
153cb9cadadSEd Warnicke    return 0;
154cb9cadadSEd Warnicke
155cb9cadadSEd Warnicke  h->address = 0xff;
156cb9cadadSEd Warnicke  h->control = 0x03;
157cb9cadadSEd Warnicke  h->protocol = clib_host_to_net_u16 (p);
158cb9cadadSEd Warnicke
159cb9cadadSEd Warnicke  /* Add header to result. */
160cb9cadadSEd Warnicke  {
161cc42db82SSwarup Nayak    void *p;
162cb9cadadSEd Warnicke    u32 n_bytes = sizeof (h[0]);
163cb9cadadSEd Warnicke
164cb9cadadSEd Warnicke    vec_add2 (*result, p, n_bytes);
165f1213b82SDamjan Marion    clib_memcpy (p, h, n_bytes);
166cb9cadadSEd Warnicke  }
167cc42db82SSwarup Nayak
168cb9cadadSEd Warnicke  return 1;
169cb9cadadSEd Warnicke}
170cb9cadadSEd Warnicke
171cc42db82SSwarup Nayakstatic u8 *
172b80c536eSNeale Rannshdlc_build_rewrite (vnet_main_t * vnm,
173b80c536eSNeale Ranns		    u32 sw_if_index,
174cc42db82SSwarup Nayak		    vnet_link_t link_type, const void *dst_address)
175cb9cadadSEd Warnicke{
176cc42db82SSwarup Nayak  hdlc_header_t *h;
177cc42db82SSwarup Nayak  u8 *rewrite = NULL;
178cb9cadadSEd Warnicke  hdlc_protocol_t protocol;
179cb9cadadSEd Warnicke
180cc42db82SSwarup Nayak  switch (link_type)
181cc42db82SSwarup Nayak    {
182b80c536eSNeale Ranns#define _(a,b) case VNET_LINK_##a: protocol = HDLC_PROTOCOL_##b; break
183cc42db82SSwarup Nayak      _(IP4, ip4);
184cc42db82SSwarup Nayak      _(IP6, ip6);
185cc42db82SSwarup Nayak      _(MPLS, mpls_unicast);
186cb9cadadSEd Warnicke#undef _
187cc42db82SSwarup Nayak    default:
188b80c536eSNeale Ranns      return (NULL);
189cc42db82SSwarup Nayak    }
190cb9cadadSEd Warnicke
191cc42db82SSwarup Nayak  vec_validate (rewrite, sizeof (*h) - 1);
192cc42db82SSwarup Nayak  h = (hdlc_header_t *) rewrite;
193cb9cadadSEd Warnicke  h->address = 0x0f;
194cb9cadadSEd Warnicke  h->control = 0x00;
195cb9cadadSEd Warnicke  h->protocol = clib_host_to_net_u16 (protocol);
196cc42db82SSwarup Nayak
197b80c536eSNeale Ranns  return (rewrite);
198cb9cadadSEd Warnicke}
199cb9cadadSEd Warnicke
200cc42db82SSwarup Nayak/* *INDENT-OFF* */
201cb9cadadSEd WarnickeVNET_HW_INTERFACE_CLASS (hdlc_hw_interface_class) = {
202cb9cadadSEd Warnicke  .name = "HDLC",
203cb9cadadSEd Warnicke  .format_header = format_hdlc_header_with_length,
204cb9cadadSEd Warnicke  .unformat_header = unformat_hdlc_header,
205b80c536eSNeale Ranns  .build_rewrite = hdlc_build_rewrite,
206b80c536eSNeale Ranns  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
207cb9cadadSEd Warnicke};
208cc42db82SSwarup Nayak/* *INDENT-ON* */
209cb9cadadSEd Warnicke
210cc42db82SSwarup Nayakstatic void
211cc42db82SSwarup Nayakadd_protocol (hdlc_main_t * pm, hdlc_protocol_t protocol, char *protocol_name)
212cb9cadadSEd Warnicke{
213cc42db82SSwarup Nayak  hdlc_protocol_info_t *pi;
214cb9cadadSEd Warnicke  u32 i;
215cb9cadadSEd Warnicke
216cb9cadadSEd Warnicke  vec_add2 (pm->protocol_infos, pi, 1);
217cb9cadadSEd Warnicke  i = pi - pm->protocol_infos;
218cb9cadadSEd Warnicke
219cb9cadadSEd Warnicke  pi->name = protocol_name;
220cb9cadadSEd Warnicke  pi->protocol = protocol;
221cb9cadadSEd Warnicke  pi->next_index = pi->node_index = ~0;
222cb9cadadSEd Warnicke
223cb9cadadSEd Warnicke  hash_set (pm->protocol_info_by_protocol, protocol, i);
224cb9cadadSEd Warnicke  hash_set_mem (pm->protocol_info_by_name, pi->name, i);
225cb9cadadSEd Warnicke}
226cb9cadadSEd Warnicke
227cc42db82SSwarup Nayakstatic clib_error_t *
228cc42db82SSwarup Nayakhdlc_init (vlib_main_t * vm)
229cb9cadadSEd Warnicke{
230cc42db82SSwarup Nayak  hdlc_main_t *pm = &hdlc_main;
231cb9cadadSEd Warnicke
232b7b92993SDave Barach  clib_memset (pm, 0, sizeof (pm[0]));
233cb9cadadSEd Warnicke  pm->vlib_main = vm;
234cb9cadadSEd Warnicke
235cb9cadadSEd Warnicke  pm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
236cb9cadadSEd Warnicke  pm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
237cb9cadadSEd Warnicke
238cb9cadadSEd Warnicke#define _(n,s) add_protocol (pm, HDLC_PROTOCOL_##s, #s);
239cb9cadadSEd Warnicke  foreach_hdlc_protocol
240cb9cadadSEd Warnicke#undef _
241cc42db82SSwarup Nayak    return vlib_call_init_function (vm, hdlc_input_init);
242cb9cadadSEd Warnicke}
243cb9cadadSEd Warnicke
244cb9cadadSEd WarnickeVLIB_INIT_FUNCTION (hdlc_init);
245cb9cadadSEd Warnicke
246cc42db82SSwarup Nayak/*
247cc42db82SSwarup Nayak * fd.io coding-style-patch-verification: ON
248cc42db82SSwarup Nayak *
249cc42db82SSwarup Nayak * Local Variables:
250cc42db82SSwarup Nayak * eval: (c-set-style "gnu")
251cc42db82SSwarup Nayak * End:
252cc42db82SSwarup Nayak */
253