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 * ppp.c: ppp support
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/ppp/ppp.h>
42cb9cadadSEd Warnicke
43cb9cadadSEd Warnicke/* Global main structure. */
44cb9cadadSEd Warnickeppp_main_t ppp_main;
45cb9cadadSEd Warnicke
46aba0fe49SCalvinu8 *
47aba0fe49SCalvinformat_ppp_protocol (u8 * s, va_list * args)
48cb9cadadSEd Warnicke{
49cb9cadadSEd Warnicke  ppp_protocol_t p = va_arg (*args, u32);
50aba0fe49SCalvin  ppp_main_t *pm = &ppp_main;
51aba0fe49SCalvin  ppp_protocol_info_t *pi = ppp_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
61aba0fe49SCalvinu8 *
62aba0fe49SCalvinformat_ppp_header_with_length (u8 * s, va_list * args)
63cb9cadadSEd Warnicke{
64aba0fe49SCalvin  ppp_main_t *pm = &ppp_main;
65aba0fe49SCalvin  ppp_header_t *h = va_arg (*args, ppp_header_t *);
66cb9cadadSEd Warnicke  u32 max_header_bytes = va_arg (*args, u32);
67cb9cadadSEd Warnicke  ppp_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, "ppp header truncated");
73cb9cadadSEd Warnicke
74cb9cadadSEd Warnicke  indent = format_get_indent (s);
75cb9cadadSEd Warnicke
76cb9cadadSEd Warnicke  s = format (s, "PPP %U", format_ppp_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    {
85aba0fe49SCalvin      ppp_protocol_info_t *pi = ppp_get_protocol_info (pm, p);
86aba0fe49SCalvin      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
97aba0fe49SCalvinu8 *
98aba0fe49SCalvinformat_ppp_header (u8 * s, va_list * args)
99cb9cadadSEd Warnicke{
100aba0fe49SCalvin  ppp_header_t *h = va_arg (*args, ppp_header_t *);
101cb9cadadSEd Warnicke  return format (s, "%U", format_ppp_header_with_length, h, 0);
102cb9cadadSEd Warnicke}
103cb9cadadSEd Warnicke
104cb9cadadSEd Warnicke/* Returns ppp protocol as an int in host byte order. */
105cb9cadadSEd Warnickeuword
106cb9cadadSEd Warnickeunformat_ppp_protocol_host_byte_order (unformat_input_t * input,
107cb9cadadSEd Warnicke				       va_list * args)
108cb9cadadSEd Warnicke{
109aba0fe49SCalvin  u16 *result = va_arg (*args, u16 *);
110aba0fe49SCalvin  ppp_main_t *pm = &ppp_main;
111cb9cadadSEd Warnicke  int p, i;
112cb9cadadSEd Warnicke
113cb9cadadSEd Warnicke  /* Numeric type. */
114aba0fe49SCalvin  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    {
126aba0fe49SCalvin      ppp_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_ppp_protocol_net_byte_order (unformat_input_t * input,
136cb9cadadSEd Warnicke				      va_list * args)
137cb9cadadSEd Warnicke{
138aba0fe49SCalvin  u16 *result = va_arg (*args, u16 *);
139aba0fe49SCalvin  if (!unformat_user (input, unformat_ppp_protocol_host_byte_order, result))
140cb9cadadSEd Warnicke    return 0;
141aba0fe49SCalvin  *result = clib_host_to_net_u16 ((u16) * result);
142cb9cadadSEd Warnicke  return 1;
143cb9cadadSEd Warnicke}
144cb9cadadSEd Warnicke
145cb9cadadSEd Warnickeuword
146cb9cadadSEd Warnickeunformat_ppp_header (unformat_input_t * input, va_list * args)
147cb9cadadSEd Warnicke{
148aba0fe49SCalvin  u8 **result = va_arg (*args, u8 **);
149aba0fe49SCalvin  ppp_header_t _h, *h = &_h;
150cb9cadadSEd Warnicke  u16 p;
151cb9cadadSEd Warnicke
152aba0fe49SCalvin  if (!unformat (input, "%U", unformat_ppp_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  {
161aba0fe49SCalvin    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  }
167aba0fe49SCalvin
168cb9cadadSEd Warnicke  return 1;
169cb9cadadSEd Warnicke}
170cb9cadadSEd Warnicke
171b80c536eSNeale Rannsstatic u8 *
172b80c536eSNeale Rannsppp_build_rewrite (vnet_main_t * vnm,
173b80c536eSNeale Ranns		   u32 sw_if_index,
174b80c536eSNeale Ranns		   vnet_link_t link_type, const void *dst_hw_address)
175cb9cadadSEd Warnicke{
176b80c536eSNeale Ranns  ppp_header_t *h;
177b80c536eSNeale Ranns  u8 *rewrite = NULL;
178cb9cadadSEd Warnicke  ppp_protocol_t protocol;
179cb9cadadSEd Warnicke
180b80c536eSNeale Ranns  switch (link_type)
181aba0fe49SCalvin    {
182b80c536eSNeale Ranns#define _(a,b) case VNET_LINK_##a: protocol = PPP_PROTOCOL_##b; break
183aba0fe49SCalvin      _(IP4, ip4);
184aba0fe49SCalvin      _(IP6, ip6);
185b80c536eSNeale Ranns      _(MPLS, mpls_unicast);
186cb9cadadSEd Warnicke#undef _
187aba0fe49SCalvin    default:
188b80c536eSNeale Ranns      return (NULL);
189aba0fe49SCalvin    }
190cb9cadadSEd Warnicke
191b80c536eSNeale Ranns  vec_validate (rewrite, sizeof (*h) - 1);
192b80c536eSNeale Ranns  h = (ppp_header_t *) rewrite;
193cb9cadadSEd Warnicke  h->address = 0xff;
194cb9cadadSEd Warnicke  h->control = 0x03;
195cb9cadadSEd Warnicke  h->protocol = clib_host_to_net_u16 (protocol);
196aba0fe49SCalvin
197b80c536eSNeale Ranns  return (rewrite);
198cb9cadadSEd Warnicke}
199cb9cadadSEd Warnicke
200aba0fe49SCalvin/* *INDENT-OFF* */
201cb9cadadSEd WarnickeVNET_HW_INTERFACE_CLASS (ppp_hw_interface_class) = {
202cb9cadadSEd Warnicke  .name = "PPP",
203cb9cadadSEd Warnicke  .format_header = format_ppp_header_with_length,
204cb9cadadSEd Warnicke  .unformat_header = unformat_ppp_header,
205b80c536eSNeale Ranns  .build_rewrite = ppp_build_rewrite,
206b80c536eSNeale Ranns  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
207cb9cadadSEd Warnicke};
208aba0fe49SCalvin/* *INDENT-ON* */
209cb9cadadSEd Warnicke
210aba0fe49SCalvinstatic void
211aba0fe49SCalvinadd_protocol (ppp_main_t * pm, ppp_protocol_t protocol, char *protocol_name)
212cb9cadadSEd Warnicke{
213aba0fe49SCalvin  ppp_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
227aba0fe49SCalvinstatic clib_error_t *
228aba0fe49SCalvinppp_init (vlib_main_t * vm)
229cb9cadadSEd Warnicke{
230aba0fe49SCalvin  ppp_main_t *pm = &ppp_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, PPP_PROTOCOL_##s, #s);
239cb9cadadSEd Warnicke  foreach_ppp_protocol;
240cb9cadadSEd Warnicke#undef _
241cb9cadadSEd Warnicke
242cb9cadadSEd Warnicke  return vlib_call_init_function (vm, ppp_input_init);
243cb9cadadSEd Warnicke}
244cb9cadadSEd Warnicke
245cb9cadadSEd WarnickeVLIB_INIT_FUNCTION (ppp_init);
246cb9cadadSEd Warnicke
247aba0fe49SCalvin/*
248aba0fe49SCalvin * fd.io coding-style-patch-verification: ON
249aba0fe49SCalvin *
250aba0fe49SCalvin * Local Variables:
251aba0fe49SCalvin * eval: (c-set-style "gnu")
252aba0fe49SCalvin * End:
253aba0fe49SCalvin */
254