xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPConfigurePacket.cpp (revision 7e66a28740b80bf87c3f91cbb9b7b58ff4ef7f0e)
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 */
KPPPConfigurePacket(uint8 code)26 KPPPConfigurePacket::KPPPConfigurePacket(uint8 code)
27 	: fCode(code),
28 	fID(0)
29 {
30 }
31 
32 
33 //!	Decodes a packet and adds its items to this object.
KPPPConfigurePacket(net_buffer * packet)34 KPPPConfigurePacket::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.
~KPPPConfigurePacket()68 KPPPConfigurePacket::~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).
76 bool
SetCode(uint8 code)77 KPPPConfigurePacket::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 */
101 bool
AddItem(const ppp_configure_item * item,int32 index)102 KPPPConfigurePacket::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.
125 bool
RemoveItem(ppp_configure_item * item)126 KPPPConfigurePacket::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.
139 ppp_configure_item*
ItemAt(int32 index) const140 KPPPConfigurePacket::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.
152 ppp_configure_item*
ItemWithType(uint8 type) const153 KPPPConfigurePacket::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 */
176 net_buffer*
ToNetBuffer(uint32 MRU)177 KPPPConfigurePacket::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