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 <KPPPConfigurePacket.h>
13#include <KPPPInterface.h>
14
15#include <core_funcs.h>
16
17
18/*!	\brief Constructor.
19
20	\param code The code value (e.g.: PPP_CONFIGURE_REQUEST) of this packet.
21*/
22KPPPConfigurePacket::KPPPConfigurePacket(uint8 code)
23	: fCode(code),
24	fID(0)
25{
26}
27
28
29//!	Decodes a packet and adds its items to this object.
30KPPPConfigurePacket::KPPPConfigurePacket(struct mbuf *packet)
31{
32	// decode packet
33	ppp_lcp_packet *header = mtod(packet, ppp_lcp_packet*);
34
35	SetID(header->id);
36	if (!SetCode(header->code))
37		return;
38
39	uint16 length = ntohs(header->length);
40
41	if (length < 6 || length > packet->m_len)
42		return;
43			// there are no items (or one corrupted item)
44
45	int32 position = 0;
46	ppp_configure_item *item;
47
48	while (position < length - 4) {
49		item = (ppp_configure_item*) (header->data + position);
50		if (item->length < 2)
51			return;
52				// found a corrupted item
53
54		position += item->length;
55		AddItem(item);
56	}
57}
58
59
60//!	Frees all items.
61KPPPConfigurePacket::~KPPPConfigurePacket()
62{
63	for (int32 index = 0; index < CountItems(); index++)
64		free(ItemAt(index));
65}
66
67
68//!	Sets the packet's code value (e.g.: PPP_CONFIGURE_REQUEST).
69bool
70KPPPConfigurePacket::SetCode(uint8 code)
71{
72	// only configure codes are allowed!
73	if (code < PPP_CONFIGURE_REQUEST || code > PPP_CONFIGURE_REJECT)
74		return false;
75
76	fCode = code;
77
78	return true;
79}
80
81
82/*!	\brief Adds a new configure item to this packet.
83
84	Make sure all values are correct because the item will be copied. If the item's
85	length field is incorrect you will get bad results.
86
87	\param item The item.
88	\param index Item's index. Adds after the last item if not specified or negative.
89
90	\return \c true if successful, \c false otherwise.
91
92	\sa ppp_configure_item
93*/
94bool
95KPPPConfigurePacket::AddItem(const ppp_configure_item *item, int32 index)
96{
97	if (!item || item->length < 2)
98		return false;
99
100	ppp_configure_item *add = (ppp_configure_item*) malloc(item->length);
101	memcpy(add, item, item->length);
102
103	bool status;
104	if (index < 0)
105		status = fItems.AddItem(add);
106	else
107		status = fItems.AddItem(add, index);
108	if (!status) {
109		free(add);
110		return false;
111	}
112
113	return true;
114}
115
116
117//!	Removes an item. The item \e must belong to this packet.
118bool
119KPPPConfigurePacket::RemoveItem(ppp_configure_item *item)
120{
121	if (!fItems.HasItem(item))
122		return false;
123
124	fItems.RemoveItem(item);
125	free(item);
126
127	return true;
128}
129
130
131//!	Returns the item at \a index or \c NULL.
132ppp_configure_item*
133KPPPConfigurePacket::ItemAt(int32 index) const
134{
135	ppp_configure_item *item = fItems.ItemAt(index);
136
137	if (item == fItems.GetDefaultItem())
138		return NULL;
139
140	return item;
141}
142
143
144//!	Returns the item of a special \a type or \c NULL.
145ppp_configure_item*
146KPPPConfigurePacket::ItemWithType(uint8 type) const
147{
148	ppp_configure_item *item;
149
150	for (int32 index = 0; index < CountItems(); index++) {
151		item = ItemAt(index);
152		if (item && item->type == type)
153			return item;
154	}
155
156	return NULL;
157}
158
159
160/*!	\brief Converts this packet into an mbuf structure.
161
162	ATTENTION: You are responsible for freeing this packet by calling \c m_freem()!
163
164	\param MRU The interface's maximum receive unit (MRU).
165	\param reserve Number of bytes to reserve at the beginning of the packet.
166
167	\return The mbuf structure or \c NULL on error (e.g.: too big for given MRU).
168*/
169struct mbuf*
170KPPPConfigurePacket::ToMbuf(uint32 MRU, uint32 reserve)
171{
172	struct mbuf *packet = m_gethdr(MT_DATA);
173	packet->m_data += reserve;
174
175	ppp_lcp_packet *header = mtod(packet, ppp_lcp_packet*);
176
177	header->code = Code();
178	header->id = ID();
179
180	uint16 length = 0;
181	ppp_configure_item *item;
182
183	for (int32 index = 0; index < CountItems(); index++) {
184		item = ItemAt(index);
185
186		// make sure we have enough space left
187		if (MRU - length < item->length) {
188			m_freem(packet);
189			return NULL;
190		}
191
192		memcpy(header->data + length, item, item->length);
193		length += item->length;
194	}
195
196	length += 4;
197	header->length = htons(length);
198	packet->m_pkthdr.len = packet->m_len = length;
199
200	return packet;
201}
202