1/*
2 * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net>
3 * Distributed under the terms of the MIT License.
4 */
5
6/*!	\class KPPPConfigurePacket
7	\brief Helper class for LCP configure packets.
8
9	This class allows iterating over configure items and adding/removing items.
10*/
11
12#include <ByteOrder.h>
13#include <net_buffer.h>
14#include <net_stack.h>
15
16#include <KPPPConfigurePacket.h>
17#include <KPPPInterface.h>
18
19#include <arpa/inet.h>
20
21
22/*!	\brief Constructor.
23
24	\param code The code value (e.g.: PPP_CONFIGURE_REQUEST) of this packet.
25*/
26KPPPConfigurePacket::KPPPConfigurePacket(uint8 code)
27	: fCode(code),
28	fID(0)
29{
30}
31
32
33//!	Decodes a packet and adds its items to this object.
34KPPPConfigurePacket::KPPPConfigurePacket(net_buffer *packet)
35{
36	// decode packet
37	NetBufferHeaderReader<ppp_lcp_packet> bufferhead(packet);
38	if (bufferhead.Status() != B_OK)
39		return;
40	ppp_lcp_packet &header = bufferhead.Data();
41
42	SetID(header.id);
43	if (!SetCode(header.code))
44		return;
45
46	uint16 length = ntohs(header.length);
47
48	if (length < 6 || length > packet->size)
49		return;
50			// there are no items (or one corrupted item)
51
52	int32 position = 0;
53	ppp_configure_item *item;
54
55	while (position < length - 4) {
56		item = (ppp_configure_item*) (header.data + position);
57		if (item->length < 2)
58			return;
59				// found a corrupted item
60
61		position += item->length;
62		AddItem(item);
63	}
64}
65
66
67//!	Frees all items.
68KPPPConfigurePacket::~KPPPConfigurePacket()
69{
70	for (int32 index = 0; index < CountItems(); index++)
71		free(ItemAt(index));
72}
73
74
75//!	Sets the packet's code value (e.g.: PPP_CONFIGURE_REQUEST).
76bool
77KPPPConfigurePacket::SetCode(uint8 code)
78{
79	// only configure codes are allowed!
80	if (code < PPP_CONFIGURE_REQUEST || code > PPP_CONFIGURE_REJECT)
81		return false;
82
83	fCode = code;
84
85	return true;
86}
87
88
89/*!	\brief Adds a new configure item to this packet.
90
91	Make sure all values are correct because the item will be copied. If the item's
92	length field is incorrect you will get bad results.
93
94	\param item The item.
95	\param index Item's index. Adds after the last item if not specified or negative.
96
97	\return \c true if successful, \c false otherwise.
98
99	\sa ppp_configure_item
100*/
101bool
102KPPPConfigurePacket::AddItem(const ppp_configure_item *item, int32 index)
103{
104	if (!item || item->length < 2)
105		return false;
106
107	ppp_configure_item *add = (ppp_configure_item*) malloc(item->length);
108	memcpy(add, item, item->length);
109
110	bool status;
111	if (index < 0)
112		status = fItems.AddItem(add);
113	else
114		status = fItems.AddItem(add, index);
115	if (!status) {
116		free(add);
117		return false;
118	}
119
120	return true;
121}
122
123
124//!	Removes an item. The item \e must belong to this packet.
125bool
126KPPPConfigurePacket::RemoveItem(ppp_configure_item *item)
127{
128	if (!fItems.HasItem(item))
129		return false;
130
131	fItems.RemoveItem(item);
132	free(item);
133
134	return true;
135}
136
137
138//!	Returns the item at \a index or \c NULL.
139ppp_configure_item*
140KPPPConfigurePacket::ItemAt(int32 index) const
141{
142	ppp_configure_item *item = fItems.ItemAt(index);
143
144	if (item == fItems.GetDefaultItem())
145		return NULL;
146
147	return item;
148}
149
150
151//!	Returns the item of a special \a type or \c NULL.
152ppp_configure_item*
153KPPPConfigurePacket::ItemWithType(uint8 type) const
154{
155	ppp_configure_item *item;
156
157	for (int32 index = 0; index < CountItems(); index++) {
158		item = ItemAt(index);
159		if (item && item->type == type)
160			return item;
161	}
162
163	return NULL;
164}
165
166
167/*!	\brief Converts this packet into an net_buffer structure.
168
169	ATTENTION: You are responsible for freeing this packet by calling \c m_freem()!
170
171	\param MRU The interface's maximum receive unit (MRU).
172	\param reserve Number of bytes to reserve at the beginning of the packet.
173
174	\return The net_buffer structure or \c NULL on error (e.g.: too big for given MRU).
175*/
176net_buffer*
177KPPPConfigurePacket::ToNetBuffer(uint32 MRU)
178{
179	net_buffer *buffer = gBufferModule->create(256);
180	if (buffer == NULL) {
181		TRACE("%s::%s: gBufferModule->create fail\n", __FILE__, __func__);
182		return(NULL);
183	}
184
185	ppp_lcp_packet *header;
186	status_t status = gBufferModule->append_size(buffer, 1492, (void **)&header);
187	if (status != B_OK) {
188		TRACE("%s::%s: gBufferModule->append_size\n", __FILE__, __func__);
189		gBufferModule->free(buffer);
190		return(NULL);
191	}
192
193	header->code = Code();
194	header->id = ID();
195
196	uint16 length = 0;
197	ppp_configure_item *item;
198
199	for (int32 index = 0; index < CountItems(); index++) {
200		item = ItemAt(index);
201
202		// make sure we have enough space left
203		if (MRU - length < item->length) {
204			gBufferModule->free(buffer);
205			return NULL;
206		}
207
208		memcpy(header->data + length, item, item->length);
209		length += item->length;
210	}
211
212	length += 4;
213	header->length = htons(length);
214
215	status = gBufferModule->trim(buffer, length);
216	if (status < B_OK) {
217		dprintf("%s::%s: gBufferModule->trim\n", __FILE__, __func__);
218		gBufferModule->free(buffer);
219		return(NULL);
220	}
221
222	return buffer;
223}
224