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