blob: 7c597bc87089024a57dace8361c3f6f6849314e6 [file] [log] [blame]
Abhay Kumar40252eb2025-10-13 13:25:53 +00001// Copyright 2023 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package procfs
15
16import (
17 "bufio"
18 "bytes"
19 "fmt"
20 "io"
21 "strconv"
22 "strings"
23
24 "github.com/prometheus/procfs/internal/util"
25)
26
27// Wireless models the content of /proc/net/wireless.
28type Wireless struct {
29 Name string
30
31 // Status is the current 4-digit hex value status of the interface.
32 Status uint64
33
34 // QualityLink is the link quality.
35 QualityLink int
36
37 // QualityLevel is the signal gain (dBm).
38 QualityLevel int
39
40 // QualityNoise is the signal noise baseline (dBm).
41 QualityNoise int
42
43 // DiscardedNwid is the number of discarded packets with wrong nwid/essid.
44 DiscardedNwid int
45
46 // DiscardedCrypt is the number of discarded packets with wrong code/decode (WEP).
47 DiscardedCrypt int
48
49 // DiscardedFrag is the number of discarded packets that can't perform MAC reassembly.
50 DiscardedFrag int
51
52 // DiscardedRetry is the number of discarded packets that reached max MAC retries.
53 DiscardedRetry int
54
55 // DiscardedMisc is the number of discarded packets for other reasons.
56 DiscardedMisc int
57
58 // MissedBeacon is the number of missed beacons/superframe.
59 MissedBeacon int
60}
61
62// Wireless returns kernel wireless statistics.
63func (fs FS) Wireless() ([]*Wireless, error) {
64 b, err := util.ReadFileNoStat(fs.proc.Path("net/wireless"))
65 if err != nil {
66 return nil, err
67 }
68
69 m, err := parseWireless(bytes.NewReader(b))
70 if err != nil {
71 return nil, fmt.Errorf("%w: wireless: %w", ErrFileParse, err)
72 }
73
74 return m, nil
75}
76
77// parseWireless parses the contents of /proc/net/wireless.
78/*
79Inter-| sta-| Quality | Discarded packets | Missed | WE
80face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
81 eth1: 0000 5. -256. -10. 0 1 0 3 0 0
82 eth2: 0000 5. -256. -20. 0 2 0 4 0 0
83*/
84func parseWireless(r io.Reader) ([]*Wireless, error) {
85 var (
86 interfaces []*Wireless
87 scanner = bufio.NewScanner(r)
88 )
89
90 for n := 0; scanner.Scan(); n++ {
91 // Skip the 2 header lines.
92 if n < 2 {
93 continue
94 }
95
96 line := scanner.Text()
97
98 parts := strings.Split(line, ":")
99 if len(parts) != 2 {
100 return nil, fmt.Errorf("%w: expected 2 parts after splitting line by ':', got %d for line %q", ErrFileParse, len(parts), line)
101 }
102
103 name := strings.TrimSpace(parts[0])
104 stats := strings.Fields(parts[1])
105
106 if len(stats) < 10 {
107 return nil, fmt.Errorf("%w: invalid number of fields in line %d, expected 10+, got %d: %q", ErrFileParse, n, len(stats), line)
108 }
109
110 status, err := strconv.ParseUint(stats[0], 16, 16)
111 if err != nil {
112 return nil, fmt.Errorf("%w: invalid status in line %d: %q", ErrFileParse, n, line)
113 }
114
115 qlink, err := strconv.Atoi(strings.TrimSuffix(stats[1], "."))
116 if err != nil {
117 return nil, fmt.Errorf("%w: parse Quality:link as integer %q: %w", ErrFileParse, qlink, err)
118 }
119
120 qlevel, err := strconv.Atoi(strings.TrimSuffix(stats[2], "."))
121 if err != nil {
122 return nil, fmt.Errorf("%w: Quality:level as integer %q: %w", ErrFileParse, qlevel, err)
123 }
124
125 qnoise, err := strconv.Atoi(strings.TrimSuffix(stats[3], "."))
126 if err != nil {
127 return nil, fmt.Errorf("%w: Quality:noise as integer %q: %w", ErrFileParse, qnoise, err)
128 }
129
130 dnwid, err := strconv.Atoi(stats[4])
131 if err != nil {
132 return nil, fmt.Errorf("%w: Discarded:nwid as integer %q: %w", ErrFileParse, dnwid, err)
133 }
134
135 dcrypt, err := strconv.Atoi(stats[5])
136 if err != nil {
137 return nil, fmt.Errorf("%w: Discarded:crypt as integer %q: %w", ErrFileParse, dcrypt, err)
138 }
139
140 dfrag, err := strconv.Atoi(stats[6])
141 if err != nil {
142 return nil, fmt.Errorf("%w: Discarded:frag as integer %q: %w", ErrFileParse, dfrag, err)
143 }
144
145 dretry, err := strconv.Atoi(stats[7])
146 if err != nil {
147 return nil, fmt.Errorf("%w: Discarded:retry as integer %q: %w", ErrFileParse, dretry, err)
148 }
149
150 dmisc, err := strconv.Atoi(stats[8])
151 if err != nil {
152 return nil, fmt.Errorf("%w: Discarded:misc as integer %q: %w", ErrFileParse, dmisc, err)
153 }
154
155 mbeacon, err := strconv.Atoi(stats[9])
156 if err != nil {
157 return nil, fmt.Errorf("%w: Missed:beacon as integer %q: %w", ErrFileParse, mbeacon, err)
158 }
159
160 w := &Wireless{
161 Name: name,
162 Status: status,
163 QualityLink: qlink,
164 QualityLevel: qlevel,
165 QualityNoise: qnoise,
166 DiscardedNwid: dnwid,
167 DiscardedCrypt: dcrypt,
168 DiscardedFrag: dfrag,
169 DiscardedRetry: dretry,
170 DiscardedMisc: dmisc,
171 MissedBeacon: mbeacon,
172 }
173
174 interfaces = append(interfaces, w)
175 }
176
177 if err := scanner.Err(); err != nil {
178 return nil, fmt.Errorf("%w: Failed to scan /proc/net/wireless: %w", ErrFileRead, err)
179 }
180
181 return interfaces, nil
182}