1 /* 2 * Copyright 2007 Oliver Ruiz Dorantes. All rights reserved. 3 * Copyright 2024, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 #include "l2cap_command.h" 7 8 #include <NetBufferUtilities.h> 9 10 11 net_buffer* 12 make_l2cap_command_reject(uint8& code, uint16 reason, uint16 mtu, uint16 scid, uint16 dcid) 13 { 14 NetBufferDeleter<> buffer(gBufferModule->create(128)); 15 if (!buffer.IsSet()) 16 return NULL; 17 18 if (reason == l2cap_command_reject::REJECTED_MTU_EXCEEDED) { 19 NetBufferPrepend<uint16> data(buffer.Get()); 20 *data = htole16(mtu); 21 } else if (reason == l2cap_command_reject::REJECTED_INVALID_CID) { 22 NetBufferPrepend<l2cap_command_reject_data> data(buffer.Get()); 23 data->invalid_cid.scid = htole16(scid); 24 data->invalid_cid.dcid = htole16(dcid); 25 } 26 27 NetBufferPrepend<l2cap_command_reject> command(buffer.Get()); 28 if (command.Status() != B_OK) 29 return NULL; 30 31 code = L2CAP_COMMAND_REJECT_RSP; 32 command->reason = (uint16)htole16(reason); 33 34 return buffer.Detach(); 35 } 36 37 38 net_buffer* 39 make_l2cap_connection_req(uint8& code, uint16 psm, uint16 scid) 40 { 41 NetBufferDeleter<> buffer(gBufferModule->create(128)); 42 if (!buffer.IsSet()) 43 return NULL; 44 45 NetBufferPrepend<l2cap_connection_req> command(buffer.Get()); 46 if (command.Status() != B_OK) 47 return NULL; 48 49 code = L2CAP_CONNECTION_REQ; 50 command->psm = htole16(psm); 51 command->scid = htole16(scid); 52 53 return buffer.Detach(); 54 } 55 56 57 net_buffer* 58 make_l2cap_connection_rsp(uint8& code, uint16 dcid, uint16 scid, uint16 result, uint16 status) 59 { 60 NetBufferDeleter<> buffer(gBufferModule->create(128)); 61 if (!buffer.IsSet()) 62 return NULL; 63 64 NetBufferPrepend<l2cap_connection_rsp> command(buffer.Get()); 65 if (command.Status() != B_OK) 66 return NULL; 67 68 code = L2CAP_CONNECTION_RSP; 69 command->dcid = htole16(dcid); 70 command->scid = htole16(scid); 71 command->result = htole16(result); 72 command->status = htole16(status); 73 74 return buffer.Detach(); 75 } 76 77 78 net_buffer* 79 make_l2cap_configuration_req(uint8& code, uint16 dcid, uint16 flags, 80 uint16* mtu, uint16* flush_timeout, l2cap_qos* flow) 81 { 82 NetBufferDeleter<> buffer(gBufferModule->create(128)); 83 if (!buffer.IsSet()) 84 return NULL; 85 86 if (mtu != NULL) { 87 struct config_option_mtu { 88 l2cap_configuration_option header; 89 uint16 value; 90 } _PACKED; 91 NetBufferPrepend<config_option_mtu> option(buffer.Get()); 92 if (option.Status() != B_OK) 93 return NULL; 94 95 option->header.type = l2cap_configuration_option::OPTION_MTU; 96 option->header.length = sizeof(option->value); 97 option->value = htole16(*mtu); 98 } 99 100 if (flush_timeout != NULL) { 101 struct config_option_flush_timeout { 102 l2cap_configuration_option header; 103 uint16 value; 104 } _PACKED; 105 NetBufferPrepend<config_option_flush_timeout> option(buffer.Get()); 106 if (option.Status() != B_OK) 107 return NULL; 108 109 option->header.type = l2cap_configuration_option::OPTION_FLUSH_TIMEOUT; 110 option->header.length = sizeof(option->value); 111 option->value = htole16(*flush_timeout); 112 } 113 114 if (flow != NULL) { 115 struct config_option_flow { 116 l2cap_configuration_option header; 117 l2cap_qos value; 118 } _PACKED; 119 NetBufferPrepend<config_option_flow> option(buffer.Get()); 120 if (option.Status() != B_OK) 121 return NULL; 122 123 option->header.type = l2cap_configuration_option::OPTION_QOS; 124 option->header.length = sizeof(option->value); 125 option->value.flags = flow->flags; 126 option->value.service_type = flow->service_type; 127 option->value.token_rate = htole32(flow->token_rate); 128 option->value.token_bucket_size = htole32(flow->token_bucket_size); 129 option->value.peak_bandwidth = htole32(flow->peak_bandwidth); 130 option->value.access_latency = htole32(flow->access_latency); 131 option->value.delay_variation = htole32(flow->delay_variation); 132 } 133 134 NetBufferPrepend<l2cap_configuration_req> command(buffer.Get()); 135 if (command.Status() != B_OK) 136 return NULL; 137 138 code = L2CAP_CONFIGURATION_REQ; 139 command->dcid = htole16(dcid); 140 command->flags = htole16(flags); 141 142 return buffer.Detach(); 143 } 144 145 146 net_buffer* 147 make_l2cap_configuration_rsp(uint8& code, uint16 scid, uint16 flags, 148 uint16 result, net_buffer* opt) 149 { 150 NetBufferDeleter<> buffer(gBufferModule->create(128)); 151 if (!buffer.IsSet()) 152 return NULL; 153 154 NetBufferPrepend<l2cap_configuration_rsp> command(buffer.Get()); 155 if (command.Status() != B_OK) 156 return NULL; 157 158 code = L2CAP_CONFIGURATION_RSP; 159 command->scid = htole16(scid); 160 command->flags = htole16(flags); 161 command->result = htole16(result); 162 163 if (opt != NULL) { 164 if (gBufferModule->append_cloned(buffer.Get(), opt, 0, opt->size) != B_OK) 165 return NULL; 166 } 167 168 return buffer.Detach(); 169 } 170 171 172 net_buffer* 173 make_l2cap_disconnection_req(uint8& code, uint16 dcid, uint16 scid) 174 { 175 NetBufferDeleter<> buffer(gBufferModule->create(128)); 176 if (!buffer.IsSet()) 177 return NULL; 178 179 NetBufferPrepend<l2cap_disconnection_req> command(buffer.Get()); 180 if (command.Status() != B_OK) 181 return NULL; 182 183 code = L2CAP_DISCONNECTION_REQ; 184 command->dcid = htole16(dcid); 185 command->scid = htole16(scid); 186 187 return buffer.Detach(); 188 } 189 190 191 net_buffer* 192 make_l2cap_disconnection_rsp(uint8& code, uint16 dcid, uint16 scid) 193 { 194 NetBufferDeleter<> buffer(gBufferModule->create(128)); 195 if (!buffer.IsSet()) 196 return NULL; 197 198 NetBufferPrepend<l2cap_disconnection_rsp> command(buffer.Get()); 199 if (command.Status() != B_OK) 200 return NULL; 201 202 code = L2CAP_DISCONNECTION_RSP; 203 command->dcid = htole16(dcid); 204 command->scid = htole16(scid); 205 206 return buffer.Detach(); 207 } 208 209 210 net_buffer* 211 make_l2cap_information_req(uint8& code, uint16 type) 212 { 213 NetBufferDeleter<> buffer(gBufferModule->create(128)); 214 if (!buffer.IsSet()) 215 return NULL; 216 217 NetBufferPrepend<l2cap_information_req> command(buffer.Get()); 218 if (command.Status() != B_OK) 219 return NULL; 220 221 code = L2CAP_INFORMATION_REQ; 222 223 command->type = htole16(type); 224 225 return buffer.Detach(); 226 } 227 228 229 net_buffer* 230 make_l2cap_information_rsp(uint8& code, uint16 type, uint16 result, uint16 _mtu) 231 { 232 NetBufferDeleter<> buffer(gBufferModule->create(128)); 233 if (!buffer.IsSet()) 234 return NULL; 235 236 NetBufferPrepend<l2cap_information_rsp> command(buffer.Get()); 237 if (command.Status() != B_OK) 238 return NULL; 239 240 code = L2CAP_INFORMATION_RSP; 241 242 command->type = htole16(type); 243 command->result = htole16(result); 244 245 if (result == l2cap_information_rsp::RESULT_SUCCESS) { 246 switch (type) { 247 case l2cap_information_req::TYPE_CONNECTIONLESS_MTU: { 248 uint16 mtu = htole16(_mtu); 249 gBufferModule->append(buffer.Get(), &mtu, sizeof(mtu)); 250 break; 251 } 252 } 253 } 254 255 return buffer.Detach(); 256 } 257